﻿using System;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Text;
using log4net;
using log4net.Config;
using INNOVACALL.Framework.Common.InnovacallExceptions;

namespace INNOVACALL.Framework.Common.Logging
{
    /// <summary>
    /// Ajouter dans l'AppConfig la variable d'environnement "Log4Net.config"
    /// definissant le chemin physique ou le fichier de configuration sera creer ou modifier.
    /// Si la variable n'existe pas le chemin par defaut se situe dans la racine du projet.
    /// </summary>
    /// <remarks>http://lutecefalco.developpez.com/tutoriels/dotnet/log4net/introduction/</remarks>
	public class Logger : _Logging_Base
    {
        /// <summary>
        /// Chemin du fichier de configuration log4net xml.
        /// </summary>
        private static string _configFilePath;

        /// <summary>
        /// Definit le nom du fichier log4net xml dans le fichier app.config.
        /// </summary>
        private const string APP_CONFIG_KEY = "Log4NetDirectory";
        
        /// <summary>
        /// Log4Net
        /// </summary>
        private static ILog Log;

        /// <summary>
        /// Singleton, Ne créer pas d'instance.
        /// </summary>
        static Logger()
        {
            Init();
        }

        /// <summary>
        /// Charge le fichier xml qui est decrie dans le fichier
        /// app.config. If un probleme à lieux un une excpetion est generée
        /// </summary>
        private static void Init()
        {
            _configFilePath = Path.Combine(AddBS(System.AppDomain.CurrentDomain.BaseDirectory), "Log4Net.config");
            CreateLogConfigFile(_configFilePath);

            if (File.Exists(_configFilePath))
                XmlConfigurator.ConfigureAndWatch(new FileInfo(_configFilePath));
            else
                throw new Exception("Impossible de trouver ou de créer le fichier " +
                                        "de configuration Log4Net: " + _configFilePath);
        }

        private static void CreateLogConfigFile(string configFilePath)
        {
            if (!File.Exists(configFilePath))
                CreateDefault(configFilePath);
        }

        private static string AddBS(string path)
        {
            string trimmedPath = path.Trim();
            return trimmedPath.EndsWith("\\") ? trimmedPath : trimmedPath + "\\";
        }

        private static void CreateDefault(string configFilePath)
        {
            string baseDirLog = Path.Combine(GetConfigFilePath(), "Logs");

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(@"<?xml version=""1.0"" encoding=""utf-8""?>");
            sb.AppendLine(@"    <log4net>");

            sb.AppendLine(@"        <appender name=""innovacallLogger"" type=""log4net.Appender.RollingFileAppender"" >");
			sb.AppendLine(@"            <file value=""" + AddBS(baseDirLog) + "innovacallLogger.log\" />");
            sb.AppendLine(@"            <appendToFile value=""true""/>");
            sb.AppendLine(@"            <maximumFileSize value=""1000KB""/>");
            sb.AppendLine(@"            <maxSizeRollBackups value=""2""/>");
            sb.AppendLine(@"            <layout type=""log4net.Layout.PatternLayout"">");
            sb.AppendLine(@"               <conversionPattern value=""%d [%t] %p %c - %m%n""/>");
            sb.AppendLine(@"            </layout>");
            sb.AppendLine(@"        </appender>");

            foreach (var flog in Enum.GetValues(typeof(enLog)))
            {
                sb.AppendLine(@"    <logger name=""" + flog.ToString() + "\">");
                sb.AppendLine(@"        <level value=""ALL""/>");
                sb.AppendLine(@"        <appender-ref ref=""innovacallLogger"" />");
                //sb.AppendLine(@"        <appender-ref ref=""" + flog.ToString() + "\" />");
                sb.AppendLine(@"    </logger>");
            }
            sb.AppendLine(@"    </log4net>");

            FileInfo info = new FileInfo(configFilePath);
            if (!Directory.Exists(info.DirectoryName))
                Directory.CreateDirectory(info.DirectoryName);

            File.WriteAllText(configFilePath, sb.ToString());
        }

        private static string GetConfigFilePath()
        {
            string configFilePath = ConfigurationManager.AppSettings[APP_CONFIG_KEY];
            if (string.IsNullOrEmpty(configFilePath))
                configFilePath = AddBS(System.AppDomain.CurrentDomain.BaseDirectory);

            return configFilePath;
        }

        public static void Error(enLog typeLog, _InnovacallExceptions_Base error)
        {
            Log = LogManager.GetLogger(typeLog.ToString());
            if (!Log.IsErrorEnabled) { return; }
            Log.Error(error.FunctionalMessage);
        }

        public static void Info(enLog typeLog, string value)
        {
            Log = LogManager.GetLogger(typeLog.ToString());
            if (!Log.IsInfoEnabled) { return; }
            Log.Info(value);
        }

        public static void Info(enLog typeLog, MethodBase method, params object[] paramValues)
        {
            Log = LogManager.GetLogger(typeLog.ToString());
            if (!Log.IsInfoEnabled) { return; }
            Log.Info(GetMethodInfo(method, paramValues));
        }

        public static void Debug(enLog typeLog, string value)
        {
            Log = LogManager.GetLogger(typeLog.ToString());
            if (Log.IsDebugEnabled)
                Log.Debug(value);
        }

        public static void Debug(enLog typeLog, MethodBase method, params object[] paramValues)
        {
            Log = LogManager.GetLogger(typeLog.ToString());
            if (Log.IsDebugEnabled)
                Log.Debug(String.Format("{0}{1}{2}", method, Environment.NewLine, GetMethodInfo(method, paramValues)));
        }

        private static string GetMethodInfo(MethodBase method, params object[] paramValues)
        {
            try
            {
                string paramValue = string.Empty;
                ParameterInfo[] parameters = method.GetParameters();
                if (parameters != null)
                {
                    for (int i = 0; i < paramValues.Length; i++)
                    {
                        string value = paramValues[i] == null ? "" : paramValues[i].ToString();
                        paramValue += String.Format("{0} = {1} {2}", parameters[i].Name, value, Environment.NewLine);
                    }
                }
                return String.Format("{0}{1}{2}", method.ToString(), Environment.NewLine, paramValue);
            }
            catch
            {
                return string.Empty;
            }
        }
    }
}
